iT邦幫忙

2023 iThome 鐵人賽

DAY 18
0

在了解兩種控制器的差異,和接收Request的處理方式,今天來介紹ORM框架MyBatis的使用方式,結合資料庫撰寫的業務邏輯,可以讓網站應用程式實現更強大的功能,本篇重點會著重於MyBatis的基本配置和使用方式,最後在用簡單的API實現CRUD範例

為何選擇 MyBatis

Java ORM生態大致可分為兩種JPA及MyBatis兩種體系,前者的優勢在於對資料庫請求,有較完整的封裝,因此使用上可以減少SQL語句的撰寫,專注在模型地設計關聯資料庫即可,後者與JPA相反除了設定模型,必須自行撰寫SQL語句執行相關邏輯,在使用上必須學習MyBatis語句的使用方式,是要考量的學習成本

魚和熊掌不可兼得,要方便開發會受限於制式的使用工具,考量未來可能有特殊的情境,需要比較彈性的方式,實現SQL語句的撰寫,或是預設的SQL查詢不適用當前情境,此時MyBatis能細部調整SQL語句的特性,就是最好的選擇

安裝 MyBatis

在開始前,別忘了自行安裝資料庫(這邊以MySql為主),可以直接用IDE內建外掛安裝套件,或將下列XML內容貼至 pom.xml中

添加依賴項目pom.xml的內容

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

// 安裝 java mysql driver 
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

Tips: mybatis-spring-boot-starter 版本,目前使用的Spring Boot版本必須支援,否則在編譯時會出現版本不相容問題,需手動設定Spring Boot支援的version,相關資訊可查看文件說明

兩個作法設定環境變數

第一個作法: 配置環境變數(Linux)
export DB_URL=jdbc:mysql://127.0.0.1:3306/{資料庫名稱}
export DB_USER=使用者
export DB_PASSWORD=使用者密碼

第二個作法: .env檔案內的變數載入環境變數中
執行 export $(xargs < .env)

配置應用程式設定 application.properties

#取得環境變數,套用至應用程式資料,用{}會從系統環境變數抓值
spring.datasource.url=${DB_URL}
spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PASSWORD}
mybatis.mapper-locations=classpath:mappers/*.xml

在資料庫建立 member 資料表DDL定義

CREATE TABLE `member` (
	`id` BIGINT(19) NOT NULL AUTO_INCREMENT,
	`account` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_general_ci',
	`password` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_general_ci',
	`name` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_general_ci',
	PRIMARY KEY (`id`) USING BTREE,
	INDEX `id` (`id`) USING BTREE
)
COLLATE='utf8mb4_general_ci'
ENGINE=InnoDB;

重點筆記:
classpath預設路徑是src/main/resources或/src/test/resources,因此classpath:mappers/*.xml可以解讀成,從src/main/resources下的mappers資料夾,尋找XML配置文件

在來尋找 src/main/resources/mappers目錄(預設沒有mappers,需要自行建立),在裡面放MyBatis Mapper XML檔案,撰寫MyBatis綁定的DAO介面,與實際執行的SQL語句

// Member.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.app.dao.MemberDao" >
    <select id="getById" resultType="User">
        SELECT * FROM members WHERE id = #{id}
    </select>

    <insert
        id="create" parameterType="com.app.dto.Member"
    >
        INSERT INTO members (account, password, name) 
        VALUES (#{account}, #{password}, #{name})
    </insert>

    <delete id="delete">
        DELETE FROM members WHERE id = #{memberId}        
    </delete>
</mapper>

在控制器注入Dao實現建立操作
定義一個Member DTO物件用來接收客戶端資料

public class Member {
    public int id;
    public String account;
    public String password;
    public String name;
}

由於是在資料庫做查詢操作,這時候定義一個抽象DAO層用來規範資料庫行為

// Location: src/main/com/app/demo/dao/MemberDao.java
import org.apache.ibatis.annotations.Mapper;
import com.app.demo.dto.Member;

@Mapper
public interface MemberDao {
    public Boolean create(String name, String account, String password);
    public Member getById(int memberId);
}

在控制器注入DAO,執行資料庫操作
打開ApiController實現CRUD操作,在開始前別忘了先在控制器注入依賴的MemberDao

@Autowired
private MemberDao memberDao;
Create:建立新資料

@PostMapping("/member")
public Map createMember(
        @RequestBody Member member) {
    memberDao.create(member);
    Map<String, Object> responseData = new HashMap<>();
    responseData.put("name", member.name);
    return responseData;
}

Read 取得會員資料

@GetMapping("/member/{memberId}")
public Map getMmeber(
        @PathVariable("memberId") int memberId) {
    Member member = memberDao.getById(memberId);
    Map<String, Object> responseData = new HashMap<>();
    System.out.printf("QeuryId: %d", memberId);
    responseData.put("queryId", memberId);
    responseData.put("data", member);
    return responseData;
}

Update 更新會員資料
這裡有個變化,利用參數的方式,將資料套用到Mapper中

首先要在Dao的方法參數中添加@param Annotation

//--- MemberDao.java
public int update(
   @Param("memberId") int memberId,
   @Param("member") Member mebmer
);

接著調整 Mapper File新增更新段落,用法將佔位字符,套用實際資料的屬性或實際值

//--- Member.xml
<update id="update">
    UPDATE members
    SET
        account = #{member.account}, password = #{member.password},
        name = #{member.name}
    WHERE id = #{memberId}
</update>
最後在控制器新增會員更新的路由規則

@PatchMapping("/member/{memberId}")
public Map updateMember(
        @RequestBody Member member,
        @PathVariable("memberId") int memberId) {
    memberDao.update(memberId, member);
    Map<String, Object> responseData = new HashMap<>();
    Member modifyMember = memberDao.getById(memberId);
    responseData.put("update_id", memberId);
    responseData.put("data", modifyMember);
    return responseData;
}

Delete 移除會員
Mapper已經定義了操作的SQL語句,只需要在DAO新增 delete方法,以及APIController建立移除的資源即可

//-- MemberDao.java
新增移除方法即可
public int delete(int memberId);

//-- ApiController.java
@DeleteMapping("/member/{memberId}")
public Map updateMember(
        @PathVariable("memberId") int memberId) {
    int deleteResult = memberDao.delete(memberId);
    Map<String, Object> responseData = new HashMap<>();
    responseData.put("delete_id", memberId);
    responseData.put("status", deleteResult);
    return responseData;
}

完成CURD的操作後,來段小結

整個操作是將執行的SQL另外定義在Mapper XML中,並且沒有實作執行SQL語句的邏輯,只需要將DAO的抽象方法與Mapper綁定對應的語句,MyBatis會將SQL語句中的佔位字符,透過預處理的方式,將實際數值套用到執行的SQL中,接著在執行SQL語句,完成相關操作,因此抽象的DAO層,專注資料庫的操作邏輯,實現與其他業務邏輯的隔離

參考文件

  1. MyBatis 文件

上一篇
第17日 傳送Form表單
下一篇
第19日 用Lombok讓你的雙手解放
系列文
掌握Java神器,駕馭SpringBoot猛獸30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言